#define _GNU_SOURCE

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "mediatypes.h"


static const char *ValidTypes[] = {
   "dvdiso",
   "medialist",
   "cdflac",
   "trackflac",
};

static void token_break(char *line, char **token, char **value){
   char *c;
   *token = line;
   *value = NULL;
   c = index(line,':');
   if (c) {
      *c=0;
      c++;
      *value = c;
      c=index(c,'\n');
      if(c) *c=0;
   }
}

static inline void cond_free(void *ptr) {
   if (ptr) free(ptr);
}

static char **dirs_to_dirlist(char* dirs){
   char **retval = NULL;
   return retval;
}

static void append_to_list(char ***list,char *new) {
   int len = 0;
   len = sizeof(*list[0])/sizeof(*list);
   *list=realloc(*list,(len+1)*sizeof(*list[0]));
   *list[len]=NULL;
   *list[len-1]=strdup(new);
}

static void free_dirlist(char **dirlist) {
   int i=0;
   while(dirlist[i]) {
      free(dirlist[i]);
      i++;
   }
}

MT_DVDISO_t *ReadDVDISOType(FILE *fd) {
   MT_DVDISO_t *ReturnValue = NULL;
   char *value = NULL, *token = NULL, *buffer= NULL;
   size_t bufcnt = 0;
   ReturnValue = malloc(sizeof(MT_DVDISO_t));
   if (ReturnValue) {
      memset(ReturnValue,0,sizeof(MT_DVDISO_t));
      while(getline(&buffer,&bufcnt,fd)>-1) {
         token_break(buffer,&token,&value);
         if (strcmp(token,"file") == 0) {
            if (ReturnValue->file == NULL) ReturnValue->file = strdup(value);
         } else if (strcmp(token,"title") == 0) {
            if (ReturnValue->title == NULL) ReturnValue->title = strdup(value);
         } else if (strcmp(token,"author") == 0) {
            if (ReturnValue->author == NULL) ReturnValue->author = strdup(value);
         } else if (strcmp(token,"cover") == 0) {
            if (ReturnValue->cover == NULL) ReturnValue->cover = strdup(value);
         }
         free(buffer);
         bufcnt = 0;
      }
   }
   return ReturnValue;
}

void SetDVDISOType(MT_DVDISO_t *node,char *file,char *title, char *author, char *cover){
   node->file=strdup(file);
   node->title=strdup(title);
   node->author=strdup(author);
   node->cover=strdup(cover);
   return;
}

void ClrDVDISOType(MT_DVDISO_t *node){
   cond_free(node->file);
   cond_free(node->title);
   cond_free(node->author);
   cond_free(node->cover);
   return;
}

int WriteDVDISOType(FILE *fd, MT_DVDISO_t *node){
   int ReturnValue = -1;
   fprintf(fd,"type:%s\n",ValidTypes[MT_DVDISO]);
   if (node->file) fprintf(fd,"file:%s\n",node->file);
   if (node->title) fprintf(fd,"title:%s\n",node->title);
   if (node->author) fprintf(fd,"author:%s\n",node->author);
   if (node->cover) fprintf(fd,"cover:%s\n",node->cover);
   return ReturnValue;
}

MT_MediaList_t *ReadMediaListType(FILE *fd){
   MT_MediaList_t *ReturnValue = NULL;
   char *buffer,*token,*value;
   size_t bufcnt = 0;
   ReturnValue = malloc(sizeof(MT_MediaList_t));
   if (ReturnValue) {
      memset(ReturnValue,0,sizeof(MT_MediaList_t));
      ReturnValue->dirlist=malloc(sizeof(char*));
      ReturnValue->dirlist[0]=NULL;
      while(getline(&buffer,&bufcnt,fd)>-1) {
         token_break(buffer,&token,&value);
        if (strcmp(token,"title") == 0) {
            if (ReturnValue->title == NULL) ReturnValue->title = strdup(value);
         } else if (strcmp(token,"author") == 0) {
            if (ReturnValue->author == NULL) ReturnValue->author = strdup(value);
         } else if (strcmp(token,"cover") == 0) {
            if (ReturnValue->cover == NULL) ReturnValue->cover = strdup(value);
         } else if (strcmp(token,"dir") == 0) {
            append_to_list(&(ReturnValue->dirlist),value);
         }
         free(buffer);
         bufcnt = 0;
      }
   }
   return ReturnValue;
}

void SetMediaListType(MT_MediaList_t *node, char *title, char *author, char *cover, char *dirs){
   node->title=strdup(title);
   node->author=strdup(author);
   node->cover=strdup(cover);
   node->dirlist = dirs_to_dirlist(dirs);
   return;
}

void ClrMediaListType(MT_MediaList_t *node){
   cond_free(node->title);
   cond_free(node->author);
   cond_free(node->cover);
   if (node->dirlist) {
      free_dirlist(node->dirlist);
      free(node->dirlist);
   }
   return;
}

int WriteMediaListType(FILE *fd, MT_MediaList_t *node){
   int ReturnValue = -1;
   int i =0;
   fprintf(fd,"type:%s\n",ValidTypes[MT_MEDIALIST]);
   if (node->title) fprintf(fd,"title:%s\n",node->title);
   if (node->author) fprintf(fd,"author:%s\n",node->author);
   if (node->cover) fprintf(fd,"cover:%s\n",node->cover);
   if (node->dirlist) {
      while(node->dirlist[i]) {
         fprintf(fd,"dir:%s\n",node->dirlist[i]);
         i++;
      }
   }
   return ReturnValue;
}

MT_CDFlac_t *NewCDFlacType(char *file, char *cue, char *title, char *author, char *cover){
   MT_CDFlac_t *ReturnValue = NULL;
   ReturnValue = malloc(sizeof(MT_CDFlac_t));
   if (ReturnValue) {
      memset(ReturnValue,0,sizeof(MT_CDFlac_t));
      SetCDFlacType(ReturnValue,file,cue,title,author,cover);
   }
   return ReturnValue;
}

void SetCDFlacType(MT_CDFlac_t *node,char *file, char *cue, char *title, char *author, char *cover){
   node->file=strdup(file);
   node->cue=strdup(cue);
   node->title=strdup(title);
   node->author=strdup(author);
   node->cover=strdup(cover);
   return;
}

void ClrCDFlacType(MT_CDFlac_t *node){
   cond_free(node->file);
   cond_free(node->cue);
   cond_free(node->title);
   cond_free(node->author);
   cond_free(node->cover);
   return;
}

int WriteCDFlacType(FILE *fd, MT_CDFlac_t *node){
   int ReturnValue = -1;
   fprintf(fd,"type:%s\n",ValidTypes[MT_CDFLAC]);
   if (node->file) fprintf(fd,"file:%s\n",node->file);
   if (node->cue) fprintf(fd,"cue:%s\n",node->cue);
   if (node->title) fprintf(fd,"title:%s\n",node->title);
   if (node->author) fprintf(fd,"author:%s\n",node->author);
   if (node->cover) fprintf(fd,"cover:%s\n",node->cover);
   return ReturnValue;
}

MT_TrackFlac_t *NewTrackFlacType(char *file, char *title, char *author, char *cover){
   MT_TrackFlac_t *ReturnValue = NULL;
   ReturnValue = malloc(sizeof(MT_TrackFlac_t));
   if (ReturnValue) {
      memset(ReturnValue,0,sizeof(MT_TrackFlac_t));
      SetTrackFlacType(ReturnValue,file,title,author,cover);
   }
   return ReturnValue;
}

void SetTrackFlacType(MT_TrackFlac_t *node,char *file, char *title, char *author, char *cover){
   node->file=strdup(file);
   node->title=strdup(title);
   node->author=strdup(author);
   node->cover=strdup(cover);
   return;
}

void ClrTrackFlacType(MT_TrackFlac_t *node){
   cond_free(node->file);
   cond_free(node->title);
   cond_free(node->author);
   cond_free(node->cover);
   return;
}

int WriteTrackFlacType(FILE *fd, MT_TrackFlac_t *node){
   int ReturnValue = -1;
   fprintf(fd,"type:%s\n",ValidTypes[MT_TRACKFLAC]);
   if (node->file) fprintf(fd,"title:%s\n",node->file);
   if (node->title) fprintf(fd,"title:%s\n",node->title);
   if (node->author) fprintf(fd,"author:%s\n",node->author);
   if (node->cover) fprintf(fd,"title:%s\n",node->cover);
   return ReturnValue;
}

void ClrMediaElement(MediaElement_t *Element) {
   return;
}

MediaElement_t *ReadTXTNode(char *nodefile) {
   MediaElement_t *ReturnValue = NULL;
   FILE *fd = NULL;
   int i;
   char *token,*value,*buffer;
   size_t bufcnt;
   fd = fopen(nodefile,"r");
   if (fd) {
      bufcnt = 0;
      while( getline(&buffer,&bufcnt,fd) > -1) {
         token_break(buffer,&token,&value);
         if( strcmp("type",token)==0) {  
            for(i=0;i<MT_MAXTYPES;i++) {
               if (strcmp(value,ValidTypes[i])==0) {
                  ReturnValue = malloc(sizeof(MediaElement_t));
                  if (ReturnValue) {
                     memset(ReturnValue,0,sizeof(MediaElement_t));
                     ReturnValue->Type=i;
                     switch (i) {
                        case  MT_DVDISO:
                           ReturnValue->Element.DVDISO = ReadDVDISOType(fd);
                           break;
                        case MT_MEDIALIST:
									ReturnValue->Element.MediaList = ReadMediaListType(fd);
                           break;
                        case MT_CDFLAC:
                           break;
                        case MT_TRACKFLAC:
                           break;
                        default:
                           break;
                     }
                  }
                  break;
               }
            }
            break;
         }
         free(buffer);
         bufcnt = 0;
      }
   }
   return ReturnValue;
}

int WriteTXTNode(MediaElement_t *Element, char *nodefile) {
   int ReturnValue = -1;
   FILE *fd = NULL;
   fd = fopen(nodefile,"w");
   if (fd) {
      switch(Element->Type) {
         case  MT_DVDISO:
            ReturnValue = WriteDVDISOType(fd,Element->Element.DVDISO);
            break;
         case MT_MEDIALIST:
            ReturnValue = WriteMediaListType(fd,Element->Element.MediaList);
            break;
         case MT_CDFLAC:
            ReturnValue = WriteCDFlacType(fd,Element->Element.CDFlac);
            break;
         case MT_TRACKFLAC:
            ReturnValue = WriteTrackFlacType(fd,Element->Element.TrackFlac);
            break;
         default:
            break;
      }
      fclose(fd);
   }
   return  ReturnValue;
}
